<script setup lang="ts" name="InfraResourceConfigForm">
import { storeToRefs } from 'pinia'
import { useAppStoreWithOut } from '@/store/modules/app'
import { filesizeConvertToBytes, filesizeConvertToTargetUnit } from '@/utils/file/helper'
import { ResourceConfigApi, ResourceClientConfigType } from '@/api/infra/resource/config'
import { getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { strToStrArr } from '@/utils'
import { DICT_TYPE } from '@/enums/dictEnums'
import { FormRules } from 'element-plus'
const appStore = useAppStoreWithOut()
const { systemConfig } = storeToRefs(appStore)

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const visible = ref(false) // 弹窗的是否展示
const title = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
const formData = ref({
  id: undefined,
  name: '',
  storage: undefined,
  remark: '',
  config: {} as ResourceClientConfigType,
  imageExts: [] as string[],
  videoExts: [] as string[],
  audioExts: [] as string[],
  textExts: [] as string[],
  applicationExts: [] as string[],
  imageSize: undefined,
  videoSize: undefined,
  audioSize: undefined,
  textSize: undefined,
  applicationSize: undefined
})
const formRules = reactive<FormRules>({
  name: [{ required: true, message: t('infra.resource.config.rules', 'name'), trigger: 'blur' }],
  storage: [{ required: true, message: t('infra.resource.config.rules', 'storage'), trigger: 'blur' }],
  config: {
    basePath: [{ required: true, message: t('infra.resource.config.rules', 'basePath'), trigger: 'blur' }],
    host: [{ required: true, message: t('infra.resource.config.rules', 'host'), trigger: 'blur' }],
    port: [{ required: true, message: t('infra.resource.config.rules', 'port'), trigger: 'blur' }],
    username: [{ required: true, message: t('infra.resource.config.rules', 'username'), trigger: 'blur' }],
    password: [{ required: true, message: t('infra.resource.config.rules', 'password'), trigger: 'blur' }],
    mode: [{ required: true, message: t('infra.resource.config.rules', 'mode'), trigger: 'blur' }],
    endpoint: [{ required: true, message: t('infra.resource.config.rules', 'endpoint'), trigger: 'blur' }],
    bucket: [{ required: true, message: t('infra.resource.config.rules', 'bucket'), trigger: 'blur' }],
    accessKey: [{ required: true, message: t('infra.resource.config.rules', 'accessKey'), trigger: 'blur' }],
    accessSecret: [{ required: true, message: t('infra.resource.config.rules', 'accessSecret'), trigger: 'blur' }],
    domain: [{ required: true, message: t('infra.resource.config.rules', 'domain'), trigger: 'blur' }]
  } as FormRules,
  imageExts: [{ required: true, message: t('infra.resource.config.rules', 'imageExts'), trigger: 'blur' }],
  videoExts: [{ required: true, message: t('infra.resource.config.rules', 'videoExts'), trigger: 'blur' }],
  audioExts: [{ required: true, message: t('infra.resource.config.rules', 'audioExts'), trigger: 'blur' }],
  textExts: [{ required: true, message: t('infra.resource.config.rules', 'textExts'), trigger: 'blur' }],
  applicationExts: [{ required: true, message: t('infra.resource.config.rules', 'applicationExts'), trigger: 'blur' }],
  imageSize: [{ required: true, message: t('infra.resource.config.rules', 'imageSize'), trigger: 'blur' }],
  videoSize: [{ required: true, message: t('infra.resource.config.rules', 'videoSize'), trigger: 'blur' }],
  audioSize: [{ required: true, message: t('infra.resource.config.rules', 'audioSize'), trigger: 'blur' }],
  textSize: [{ required: true, message: t('infra.resource.config.rules', 'textSize'), trigger: 'blur' }],
  applicationSize: [{ required: true, message: t('infra.resource.config.rules', 'applicationSize'), trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const sizeType = reactive([
  {
    label: 'MB',
    value: 'MB'
  },
  {
    label: 'KB',
    value: 'KB'
  }
])
const imageSizeType = ref('KB')
const videoSizeType = ref('KB')
const audioSizeType = ref('KB')
const textSizeType = ref('KB')
const applicationSizeType = ref('KB')

const imageChecked = ref(false)
const videoChecked = ref(false)
const audioChecked = ref(false)
const textChecked = ref(false)
const applicationChecked = ref(false)
const sizeChange = (v, type) => {
  formData.value[type] = filesizeConvertToTargetUnit(filesizeConvertToBytes(formData.value[type], v === 'MB' ? 'KB' : 'MB'), v)
}

/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  visible.value = true
  title.value = t('action', type)
  formType.value = type
  resetForm()
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      const data = await ResourceConfigApi.detail(id)
      data.imageSize = filesizeConvertToTargetUnit(data.imageSize, imageSizeType.value)
      data.videoSize = filesizeConvertToTargetUnit(data.videoSize, videoSizeType.value)
      data.audioSize = filesizeConvertToTargetUnit(data.audioSize, audioSizeType.value)
      data.textSize = filesizeConvertToTargetUnit(data.textSize, textSizeType.value)
      data.applicationSize = filesizeConvertToTargetUnit(data.applicationSize, applicationSizeType.value)
      data.imageExts = strToStrArr(data.imageExts)
      if (data.imageExts.includes('image/*') && data.imageExts.length === 1) {
        imageChecked.value = true
      }
      data.videoExts = strToStrArr(data.videoExts)
      if (data.videoExts.includes('video/*') && data.videoExts.length === 1) {
        videoChecked.value = true
      }
      data.audioExts = strToStrArr(data.audioExts)
      if (data.audioExts.includes('audio/*') && data.audioExts.length === 1) {
        audioChecked.value = true
      }
      data.textExts = strToStrArr(data.textExts)
      if (data.textExts.includes('text/*') && data.textExts.length === 1) {
        textChecked.value = true
      }
      data.applicationExts = strToStrArr(data.applicationExts)
      if (data.applicationExts.includes('application/*') && data.applicationExts.length === 1) {
        applicationChecked.value = true
      }
      formData.value = data
    } finally {
      formLoading.value = false
    }
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  if (!formRef) return
  const valid = await formRef.value.validate()
  if (!valid) return
  // 提交请求
  formLoading.value = true
  try {
    const data = formData.value as any
    data.imageSize = filesizeConvertToBytes(data.imageSize, imageSizeType.value)
    data.videoSize = filesizeConvertToBytes(data.videoSize, videoSizeType.value)
    data.audioSize = filesizeConvertToBytes(data.audioSize, audioSizeType.value)
    data.textSize = filesizeConvertToBytes(data.textSize, textSizeType.value)
    data.applicationSize = filesizeConvertToBytes(data.applicationSize, applicationSizeType.value)
    data.imageExts = data.imageExts.join(',')
    data.videoExts = data.videoExts.join(',')
    data.audioExts = data.audioExts.join(',')
    data.textExts = data.textExts.join(',')
    data.applicationExts = data.applicationExts.join(',')
    if (formType.value === 'create') {
      await ResourceConfigApi.create(data)
      message.success(t('message', 'createSuccess'))
    } else {
      await ResourceConfigApi.update(data)
      message.success(t('message', 'updateSuccess'))
    }
    visible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
    name: '',
    storage: undefined,
    remark: '',
    config: {} as ResourceClientConfigType,
    imageExts: [] as string[],
    videoExts: [] as string[],
    audioExts: [] as string[],
    textExts: [] as string[],
    applicationExts: [] as string[],
    imageSize: undefined,
    videoSize: undefined,
    audioSize: undefined,
    textSize: undefined,
    applicationSize: undefined
  }
  imageSizeType.value = 'KB'
  videoSizeType.value = 'KB'
  audioSizeType.value = 'KB'
  textSizeType.value = 'KB'
  applicationSizeType.value = 'KB'

  imageChecked.value = false
  videoChecked.value = false
  audioChecked.value = false
  textChecked.value = false
  applicationChecked.value = false
  formRef.value?.resetFields()
}

const extCheckedChange = (v, type) => {
  console.log(v, type)
  switch (type) {
    case 'image':
      if (v) {
        formData.value.imageExts = ['image/*']
      } else {
        formData.value.imageExts = []
      }
      break
    case 'video':
      if (v) {
        formData.value.videoExts = ['video/*']
      } else {
        formData.value.videoExts = []
      }
      break
    case 'audio':
      if (v) {
        formData.value.audioExts = ['audio/*']
      } else {
        formData.value.audioExts = []
      }
      break
    case 'text':
      if (v) {
        formData.value.textExts = ['text/*']
      } else {
        formData.value.textExts = []
      }
      break
    case 'application':
      if (v) {
        formData.value.applicationExts = ['application/*']
      } else {
        formData.value.applicationExts = []
      }
      break
  }
}

const extSelectedChange = (v, type) => {
  console.log(v, type)
  if (v.includes('image/*') && v.length > 1) {
    imageChecked.value = false
    const index = v.findIndex(item => item === 'image/*')
    v.splice(index, 1)
  }
  if (v.includes('video/*') && v.length > 1) {
    videoChecked.value = false
    const index = v.findIndex(item => item === 'video/*')
    v.splice(index, 1)
  }
  if (v.includes('audio/*') && v.length > 1) {
    audioChecked.value = false
    const index = v.findIndex(item => item === 'audio/*')
    v.splice(index, 1)
  }
  if (v.includes('text/*') && v.length > 1) {
    textChecked.value = false
    const index = v.findIndex(item => item === 'text/*')
    v.splice(index, 1)
  }
  if (v.includes('application/*') && v.length > 1) {
    applicationChecked.value = false
    const index = v.findIndex(item => item === 'application/*')
    v.splice(index, 1)
  }
}
</script>

<template>
  <Dialog v-model="visible" :title="title" type="scroll" height="56vh" width="1024px">
    <el-form ref="formRef" v-loading="formLoading && systemConfig.loadingType === 'module'" :model="formData" :rules="formRules" label-width="120px">
      <div class="el-form-group">
        <el-form-item :label="t('infra.resource.config', 'name')" prop="name">
          <el-input v-model="formData.name" clearable :placeholder="t('infra.resource.config.rules', 'name')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'storage')" prop="storage">
          <el-select v-model="formData.storage" clearable :disabled="formData.id !== undefined" :placeholder="t('infra.resource.config.rules', 'storage')">
            <el-option v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
        </el-form-item>
      </div>
      <!-- DB -->
      <!-- Local / FTP / SFTP -->
      <el-form-item v-if="formData.storage && formData.storage >= 10 && formData.storage <= 12" :label="t('infra.resource.config', 'basePath')" prop="config.basePath">
        <el-input v-model="formData.config.basePath" clearable :placeholder="t('infra.resource.config.rules', 'basePath')" />
      </el-form-item>
      <div v-if="formData.storage && formData.storage >= 11 && formData.storage <= 12" class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'host')" prop="config.host">
          <el-input v-model="formData.config.host" clearable :placeholder="t('infra.resource.config.rules', 'host')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'port')" prop="config.port">
          <el-input-number v-model="formData.config.port" clearable :min="0" :placeholder="t('infra.resource.config.rules', 'port')" />
        </el-form-item>
      </div>
      <div v-if="formData.storage && formData.storage >= 11 && formData.storage <= 12" class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'username')" prop="config.username">
          <el-input v-model="formData.config.username" clearable :placeholder="t('infra.resource.config.rules', 'username')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'password')" prop="config.password">
          <el-input v-model="formData.config.password" clearable :placeholder="t('infra.resource.config.rules', 'password')" />
        </el-form-item>
      </div>
      <el-form-item v-if="formData.storage === 11" :label="t('infra.resource.config', 'mode')" prop="config.mode">
        <el-radio-group v-model="formData.config.mode">
          <el-radio key="Active" value="Active">{{ t('infra.resource.config', 'active') }}</el-radio>
          <el-radio key="Passive" value="Passive">{{ t('infra.resource.config', 'passive') }}</el-radio>
        </el-radio-group>
      </el-form-item>
      <!-- S3 -->
      <div v-if="formData.storage === 20" class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'endpoint')" prop="config.endpoint">
          <el-input v-model="formData.config.endpoint" clearable :placeholder="t('infra.resource.config.rules', 'endpoint')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'bucket')" prop="config.bucket">
          <el-input v-model="formData.config.bucket" clearable :placeholder="t('infra.resource.config.rules', 'bucket')" />
        </el-form-item>
      </div>
      <div v-if="formData.storage === 20" class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'accessKey')" prop="config.accessKey">
          <el-input v-model="formData.config.accessKey" clearable :placeholder="t('infra.resource.config.rules', 'accessKey')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'accessSecret')" prop="config.accessSecret">
          <el-input v-model="formData.config.accessSecret" clearable :placeholder="t('infra.resource.config.rules', 'accessSecret')" />
        </el-form-item>
      </div>
      <!-- 通用 -->
      <el-form-item v-if="formData.storage === 20" :label="t('infra.resource.config', 'domain')">
        <!-- 无需参数校验，所以去掉 prop -->
        <el-input v-model="formData.config.domain" clearable :placeholder="t('infra.resource.config.rules', 'domain')" />
      </el-form-item>
      <el-form-item v-else-if="formData.storage" :label="t('infra.resource.config', 'domain')" prop="config.domain">
        <el-input v-model="formData.config.domain" clearable :placeholder="t('infra.resource.config.rules', 'domain')" />
      </el-form-item>
      <div class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'imageExts')" prop="imageExts">
          <el-select v-model="formData.imageExts" multiple collapse-tags collapse-tags-tooltip filterable allow-create clearable :placeholder="t('infra.resource.config.rules', 'imageExts')" @change="v => extSelectedChange(v, 'image')">
            <el-option v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_RESOURCE_IMAGE_EXT)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
          <el-checkbox v-model="imageChecked" :label="t('infra.resource.config', 'all')" border @change="v => extCheckedChange(v, 'image')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'imageSize')" prop="imageSize">
          <el-input v-model="formData.imageSize" clearable type="number" :min="0" :placeholder="t('infra.resource.config.placeholder', 'size')">
            <template #append>
              <el-select v-model="imageSizeType" style="width: 70px" @change="v => sizeChange(v, 'imageSize')">
                <el-option v-for="item in sizeType" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </template>
          </el-input>
        </el-form-item>
      </div>
      <div class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'videoExts')" prop="videoExts">
          <el-select v-model="formData.videoExts" multiple collapse-tags collapse-tags-tooltip filterable allow-create clearable :placeholder="t('infra.resource.config.rules', 'videoExts')" @change="v => extSelectedChange(v, 'video')">
            <el-option v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_RESOURCE_VIDEO_EXT)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
          <el-checkbox v-model="videoChecked" :label="t('infra.resource.config', 'all')" border @change="v => extCheckedChange(v, 'video')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'videoSize')" prop="videoSize">
          <el-input v-model="formData.videoSize" clearable type="number" :min="0" :placeholder="t('infra.resource.config.placeholder', 'size')">
            <template #append>
              <el-select v-model="videoSizeType" style="width: 70px" @change="v => sizeChange(v, 'videoSize')">
                <el-option v-for="item in sizeType" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </template>
          </el-input>
        </el-form-item>
      </div>
      <div class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'audioExts')" prop="audioExts">
          <el-select v-model="formData.audioExts" multiple collapse-tags collapse-tags-tooltip filterable allow-create clearable :placeholder="t('infra.resource.config.rules', 'audioExts')" @change="v => extSelectedChange(v, 'audio')">
            <el-option v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_RESOURCE_AUDIO_EXT)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
          <el-checkbox v-model="audioChecked" :label="t('infra.resource.config', 'all')" border @change="v => extCheckedChange(v, 'audio')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'audioSize')" prop="audioSize">
          <el-input v-model="formData.audioSize" clearable type="number" :min="0" :placeholder="t('infra.resource.config.placeholder', 'size')">
            <template #append>
              <el-select v-model="audioSizeType" style="width: 70px" @change="v => sizeChange(v, 'audioSize')">
                <el-option v-for="item in sizeType" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </template>
          </el-input>
        </el-form-item>
      </div>
      <div class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'textExts')" prop="textExts">
          <el-select v-model="formData.textExts" multiple collapse-tags collapse-tags-tooltip filterable allow-create clearable :placeholder="t('infra.resource.config.rules', 'textExts')" @change="v => extSelectedChange(v, 'text')">
            <el-option v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_RESOURCE_TEXT_EXT)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
          <el-checkbox v-model="textChecked" :label="t('infra.resource.config', 'all')" border @change="v => extCheckedChange(v, 'text')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'textSize')" prop="textSize">
          <el-input v-model="formData.textSize" clearable type="number" :min="0" :placeholder="t('infra.resource.config.placeholder', 'size')">
            <template #append>
              <el-select v-model="textSizeType" style="width: 70px" @change="v => sizeChange(v, 'textSize')">
                <el-option v-for="item in sizeType" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </template>
          </el-input>
        </el-form-item>
      </div>
      <div class="el-form-group mt-6px">
        <el-form-item :label="t('infra.resource.config', 'applicationExts')" prop="applicationExts">
          <el-select v-model="formData.applicationExts" multiple collapse-tags collapse-tags-tooltip filterable allow-create clearable :placeholder="t('infra.resource.config.rules', 'applicationExts')" @change="v => extSelectedChange(v, 'application')">
            <el-option v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_RESOURCE_APPLICATION_EXT)" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
          <el-checkbox v-model="applicationChecked" :label="t('infra.resource.config', 'all')" border @change="v => extCheckedChange(v, 'application')" />
        </el-form-item>
        <el-form-item :label="t('infra.resource.config', 'applicationSize')" prop="applicationSize">
          <el-input v-model="formData.applicationSize" clearable type="number" :min="0" :placeholder="t('infra.resource.config.placeholder', 'size')">
            <template #append>
              <el-select v-model="applicationSizeType" style="width: 70px" @change="v => sizeChange(v, 'applicationSize')">
                <el-option v-for="item in sizeType" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </template>
          </el-input>
        </el-form-item>
      </div>
      <el-form-item :label="t('common', 'remark')" prop="remark">
        <el-input v-model="formData.remark" clearable :placeholder="t('common.rules', 'remark')" type="textarea" />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="visible = false">{{ t('action', 'cancel') }}</el-button>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">{{ t('action', 'confirm') }}</el-button>
    </template>
  </Dialog>
</template>

<style scoped lang="scss">
.el-form{
  margin-right: -6px;
}

.el-form-group {
  display: flex;
  flex: 1;

  .el-form-item {
    flex: 1;
    margin: 0;
  }

  .el-form-item+.el-form-item {
    margin: 0;
  }
}

.el-form-group + .el-form-item{
  margin-top: 6px;
}
</style>
